<template>
    <div class="mygps-viewer">
        <div id="map" class="map" ref="mapCom"></div>
        <switchMap ref="switchMapRef" />
        <routeDialog ref="routeDialogRef" />
        <div ref="popup" class="popup" v-show="ShowAis">
            <div class="info">
                <ul v-if="ShowAis" style="list-style-type: none">
                    <li>浮标名称：{{ nowBuoys?.deviceName }}</li>
                    <li>浮标编号：{{ nowBuoys?.terminalPhoneNo }}</li>
                    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;经度：{{ nowBuoys?.lng ? nowBuoys.lng / 1000000 : 0 }}</li>
                    <li>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;纬度：{{ nowBuoys?.lat ? nowBuoys.lat / 1000000 : 0  }}</li>
                    <li>数据时间：{{ nowBuoys?.gpsTime }}</li>
                </ul>
            </div>
        </div>
        <div class="set">
            <el-button  @click="distance()" v-show="!isDistance">测距</el-button>
            <el-button  @click="cancal()"  v-show="isDistance">取消测距</el-button>
        </div>
    </div>
</template>

<script lang="ts" setup name="monitor-map">
// 'AisQuery','startAnimation','stopAnimation'
import { onMounted, ref, onActivated, onDeactivated, onUnmounted } from 'vue';

const switchMapRef = ref<InstanceType<typeof switchMap>>();     // 图层切换组件
const routeDialogRef = ref<InstanceType<typeof routeDialog>>();

import "ol/ol.css";
import { Tile as TileLayer } from "ol/layer";

import { Map, View, Feature } from 'ol';
import Overlay from 'ol/Overlay';
import XYZ from "ol/source/XYZ";
import WMTS from "ol/source/WMTS";
import { WMTS as WMTSTileGrid } from 'ol/tilegrid';
import * as control from 'ol/control'
import { format } from 'ol/coordinate.js';
import * as style from "ol/style";
import { Style, Fill, Stroke, Circle as sCircle, Icon } from "ol/style";
import VectorSource from 'ol/source/Vector'
import VectorLayer from 'ol/layer/Vector'
import { Pixel } from 'ol/pixel'
import { Point, Geometry } from "ol/geom";
import Draw from 'ol/interaction/Draw';
import { unByKey } from 'ol/Observable';
import { getLength } from 'ol/sphere';
import url from '../../../public/static/ccflowRightNextAdmin.png';

import switchMap from './component/switch-map.vue';
import routeDialog from './component/routeDialog.vue';

import { getAPI } from "/@/axios-utils";
// import { Jt808DataApi } from '/@/api-services/api';
// import { MYGPSJT808DATAOutput } from '/@/api-services/models';

const mapCom = ref(null);            // 地图容器
const map = ref<Map | undefined>();   // 地图实例

const showMap = ref(false);         // 天地图显示模式切换
const showSeaMap = ref(true);       // 海图显示模式切换
const ShowAis = ref(false);

const overlay = ref();
const popup = ref();
// const nowBuoys = ref<MYGPSJT808DATAOutput>();
const isDistance = ref(false);

const helpTooltipElement = ref()
const feature = ref();
const helpTooltip = ref();
const draw = ref();
const measureTooltipElement = ref();
const measureTooltip = ref();
const listener = ref();
const mapMouseMove = ref();
const drawLayers = ref([]);
const drawElements = ref([]);

/**
 * 在组件被挂载之后事件
 */
onMounted(async () => {
    initMap();  // 初始化地图
    switchMapRef.value?.ShowSwitch(map);    // 初始化图层切换组件

	AddBuoys();             // 添加浮标图标
});

/**
 * 添加浮标信息
 */
const AddBuoys = async () => {
    // // 获取浮标信息
    // let res = await await getAPI(Jt808DataApi).apiJt808DataListGet();
    // let BuoysInfoData = res.data.result ?? [];

    // // 绘制浮标图标
    // let iconFeatures = DrawBuoys(BuoysInfoData);

    // // 创建矢量容器，将图标添加进容器中
    // let vectorSource = new VectorSource({
    //     features: iconFeatures
    // })

    // // 创建矢量图层
    // let vectorLayer = new VectorLayer({
    //     source: vectorSource,
    // })

    // vectorLayer.set('layerName', 'buoys');
    // // 添加图层到地图中
    // map.value?.addLayer(vectorLayer);
}

// /**
//  * 绘制浮标图标
//  * @param AisInfoData Ais信息数组
//  */
// const DrawBuoys = (AisInfoData: MYGPSJT808DATAOutput[]) => {
//     let iconFeatures: Feature<Point>[] = [];
// 	// 创建图标样式

//     AisInfoData.forEach((e) => {
//         const name = e.terminalPhoneNo ?? "未知";

// 		let Longitude = e.lng ? e.lng / 1000000 : 0;
//         let Latitude = e.lat ? e.lat / 1000000 : 0;

//         // let Longitude = e.lon;
//         // let Latitude = e.lat;
// 		let iconStyle = BuoysStyle(name);      
//         // 创建要素
//         let iconFeature = new Feature({
//             geometry: new Point([Longitude, Latitude]), // 图标展示的位置
//             projection: 'EPSG:4326',
//             population: 4000,
//             rainfall: 500,
//         });

//         iconFeature.setId(name);            // 设置图标ID
//         iconFeature.setProperties({         // 设置附加属性
//             attribute: { buoys: e },
//         })

//         iconFeature.setStyle(iconStyle);    // 把样式应用到图标上

//         iconFeatures.push(iconFeature);     // 添加图标到图标数组中
//     });

//     return iconFeatures;
// }

const BuoysStyle = (name: string) => {
    // 创建图标样式
    let iconStyle = new style.Style({
        image: new Icon({
            src: url
        }),
        text: new style.Text({
            // 显示文本，数字需要转换为文本string类型！
            text: name,
            //文字填充色
            fill: new style.Fill({
                color: '#666'
            }),
            //文字边界宽度与颜色
            stroke: new style.Stroke({
                color: '#fff',
                width: 3
            }),
            offsetX: 50,
            offsetY: -15,
        })
    })
    return iconStyle;
}

/**
 * 在组件被卸载之后事件
 */
onUnmounted(() => {

})

/**
 * 组件挂载时的生命周期执行的方法
 */
onActivated(() => {

})

/**
 * 离开当前组件的生命周期执行的方法
 */
onDeactivated(() => {

})

/**
 * 初始化地图
 */
const initMap = async () => {
    // 注册一个覆盖物
    overlay.value = new Overlay({
        element: popup.value, // 弹窗标签，在html里
        stopEvent: false,
        positioning: "bottom-center",
        offset: [150, 150],
    })

    // 总览控件（鹰眼、小地图）
    let overviewMapControl = new control.OverviewMap({
        className: 'ol-overviewmap ol-custom-overviewmap',
        layers: [
            new TileLayer({
                source: new XYZ({
                    'url': 'http://t{0-7}.tianditu.com/DataServer?x={x}&y={y}&l={z}&T=vec_c&tk=53cfe6418a1f95c79a8ddfef9173ea64',
                    'projection': "EPSG:4326",
                })
            })
        ],
        collapseLabel: '\u00BB',
        label: '\u00AB',
        collapsed: false
    });

    let scaleLine = new control.ScaleLine({				// 实例化一个ScaleLine类的实例并加入到地图
        className: 'ol-scale-line',//CSS类名称,默认'ol-scale-line'
        units: 'metric',//单位,默认'metric'
        //如果要使控件在地图视口之外呈现，请指定一个目标
        //target:document.getElementById('box'),
        //比例尺单位
        //'degrees'		//度
        //'imperial'	//英制英尺
        //'us'			//美制英尺
        //'nautical'	//海里
        //'metric'		//公制
    });

    let mousePosition = new control.MousePosition({		// 实例化坐标拾取控件，并加入地图
        className: 'ol-mouse-position', //css名称，默认'ol-mouse-position'
        coordinateFormat: function (param) {
            if (param != undefined) {
                return format(param, '{x}, {y}', 6);
            }
            else {
                return "";
            }
        }, //坐标格式
        // projection: 'EPSG:4326',//投影方式
        //如果要使控件在地图视口之外呈现，请指定一个目标
        //target:document.getElementById('box'),
    });

	let e;
	let t;
	for (e = [], t = 0; t < 13; t++){
		e.push(4891.9698102506845 / Math.pow(2, t));
	}

    map.value = new Map({
        target: "map",
        view: new View({
            center: [118.80, 24.58],
            projection: 'EPSG:4326',
            zoom: 10,
            minZoom: 2,
            maxZoom: 18,
        }),
        //overlays: [overlay.value], // 绑定一个覆盖物
        layers: [
            new TileLayer({		// 瓦片图层
                source: new XYZ({
                    url: "http://t{0-4}.tianditu.gov.cn/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=f6a024281b465b39f7f7c293a7012c80"
                }),
                visible: showMap.value
            }),
            new TileLayer({	// 地理信息图层
                source: new XYZ({
                    url: "http://t{0-4}.tianditu.gov.cn/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=f6a024281b465b39f7f7c293a7012c80"
                }),
                visible: showMap.value
            }),
            new TileLayer({		// 瓦片图层
                source: new XYZ({
                    url: "http://t{0-4}.tianditu.gov.cn/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=f6a024281b465b39f7f7c293a7012c80"
                }),
                visible: !showMap.value
            }),
            new TileLayer({	// 地理信息图层
                source: new XYZ({
                    url: "http://t{0-4}.tianditu.gov.cn/DataServer?T=cia_w&x={x}&y={y}&l={z}&tk=f6a024281b465b39f7f7c293a7012c80"
                }),
                visible: !showMap.value
            }),
			new TileLayer({	// 地理信息图层
                source: new WMTS({
					url: "https://enavapp.nhhb.org.cn/arcgis/services/SouthChinaENCWater",
					layer: 'SouthChinaENCWater',      	// 图层名
					style: 'default',        			// 在WMTS capabilities文档中对应的样式名，一定要写，否则会加载失败 
					matrixSet: 'default028mm',          // 投影坐标系矩阵集，一定要和WMTS capabilities文档中一致，否则会加载失败
					projection: "EPSG:3857",	// 投影坐标系
					format: 'image/png',                // 图片格式 
					version: '1.0.0',                   // WMTS版本
					requestEncoding: 'KVP',             // 请求的编码方式，默认就是'KVP'   
					wrapX: !0,          
					tileGrid:  new WMTSTileGrid({
						origin: [-20037508.342787, 20037508.342787],
						resolutions: e,
						tileSize: [256, 256],
						matrixIds: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
					})              					// 投影坐标系
				}),
                visible: showSeaMap.value
            }),
        ],
        controls: control.defaults().extend([
            new control.ZoomSlider(), new control.Zoom(), overviewMapControl, mousePosition, scaleLine
        ]),
    });
    map.value.addOverlay(overlay.value);

    map.value.on('singleclick', mapClick);  // 地图图标点击事件
    map.value.on('pointermove', mapMoveIn); // 地图图标移入事件
}

/**
 * 地图图标点击事件
 * @param evt 
 */
const mapClick = (evt: { pixel: any; }) => {
    if (map.value == null) return;

    const features = map.value.getFeaturesAtPixel(evt.pixel)
    if (features != null) {
        if (map.value.hasFeatureAtPixel(evt.pixel) && features[0].getProperties().attribute != undefined) {
            if (features[0].getProperties().attribute["buoys"] != null) {
                routeDialogRef.value?.openDialog(features[0].getProperties().attribute["buoys"].terminalPhoneNo);
            }
        }
    }
    
}

/**
 * 地图图标移入事件
 * @param evt 
 */
const mapMoveIn = (evt: { pixel: Pixel; coordinate: any; }) => {
    if (map.value == null) return;
    // console.log("mapMoveIn");

    if (map.value.hasFeatureAtPixel(evt.pixel)) {
        map.value.getViewport().style.cursor = "pointer";
        const features = map.value.getFeaturesAtPixel(evt.pixel)
        if(features[0].getProperties().attribute != null){
			if (features[0].getProperties().attribute["buoys"] != null) { 
				// nowBuoys.value = features[0].getProperties().attribute["buoys"];
				ShowAis.value = true;

				let coordinates = evt.coordinate; // 获取坐标
                overlay.value.setPosition(coordinates) // 设置覆盖物出现的位置
			}
			//console.log(features[0].getProperties());
		}
    } else {
        map.value.getViewport().style.cursor = "inherit";
        overlay.value.setPosition(undefined) // 隐藏覆盖物
        ShowAis.value = false;
    }

}

/**
 * 测距
 */
const distance = () => {

    isDistance.value = true;

    let source = new VectorSource()
    const layer = new VectorLayer({
        source: source,
        style: new Style({
            fill: new Fill({
                color: 'rgba(255, 255, 255, 0.2)',
            }),
            stroke: new Stroke({
                color: '#ffcc33',
                width: 4,
            }),
            image: new sCircle({
                radius: 7,
                fill: new Fill({
                    color: '#ffcc33',
                }),
            }),
        }),
    });

    mapMouseMove.value = map.value?.on('pointermove', (ev) => {
        let helpMsg = '点击开始测量'
        if (feature.value) {
            helpMsg = '双击结束测量'
        }
        helpTooltipElement.value.innerHTML = helpMsg;
        helpTooltip.value.setPosition(ev.coordinate);
        helpTooltipElement.value.classList.remove('hidden')
    })

    map.value?.getViewport().addEventListener('mouseout', function () {
        helpTooltipElement.value.classList.add('hidden');
    });

    draw.value = new Draw({
        source,
        type: 'LineString',
        style: new Style({
            fill: new Fill({
                color: 'rgba(255, 255, 255, 0.2)',
            }),
            stroke: new Stroke({
                color: 'rgba(0, 0, 0, 0.5)',
                lineDash: [10, 10],
                width: 4,
            }),
            image: new sCircle({
                radius: 5,
                stroke: new Stroke({
                    color: 'rgba(0, 0, 0, 0.7)',
                }),
                fill: new Fill({
                    color: 'rgba(255, 255, 255, 0.2)',
                }),
            }),
        }),
    });

    // 开始绘制
    draw.value.on('drawstart', (evt: { feature: any; coordinate: any; }) => {
        feature.value = evt.feature;

        let tooltipCoord = evt.coordinate;

        listener.value = feature.value.getGeometry().on('change', function (evt: { target: any; }) {
            const geom = evt.target;
            let output = formatLength(geom);
            tooltipCoord = geom.getLastCoordinate();
            measureTooltipElement.value.innerHTML = output;
            measureTooltip.value.setPosition(tooltipCoord);
        });
    });

    // 双击绘制完成
    draw.value.on('drawend', () => {
        measureTooltipElement.value.className = 'ol-tooltip ol-tooltip-static';
        measureTooltip.value.setOffset([0, -7]);
        feature.value = null;
        measureTooltipElement.value = null;
        createMeasureTooltip();
        unByKey(listener.value);
    });

    // 格式化长度
    const formatLength = function (line: Geometry) {
        const length = getLength(line);
        // console.log(length)
        let output;
        output = Math.round(length * 10000) / 100 + ' ' + 'km';
        return output;
    };

    createHelpTooltip()
    createMeasureTooltip()
    map.value?.addLayer(layer)
    // drawLayers.value.push(layer)
    map.value?.addInteraction(draw.value);
}

/**
 * 取消绘制
 */
const cancal = () => {
    isDistance.value = false;
    
    for (let i = 0; i < drawLayers.value.length; i++) {
        map.value?.removeLayer(drawLayers.value[i])
    }
    for (let i = 0; i < drawElements.value.length; i++) {
        map.value?.removeOverlay(drawElements.value[i])
    }
    drawLayers.value = []
    drawElements.value = []
    map.value?.removeInteraction(draw.value)
    unByKey(mapMouseMove.value);
};

const createMeasureTooltip = () => {
    if (measureTooltipElement.value) {
        measureTooltipElement.value.parentNode?.removeChild(measureTooltipElement.value);
    }
    measureTooltipElement.value = document.createElement('div');
    measureTooltipElement.value.className = 'ol-tooltip ol-tooltip-measure';
    measureTooltip.value = new Overlay({
        element: measureTooltipElement.value,
        offset: [0, -15],
        positioning: 'bottom-center',
        stopEvent: false,
        insertFirst: false,
    });
    // drawElements.value.push(measureTooltip.value)
    map.value?.addOverlay(measureTooltip.value);
};

const createHelpTooltip = () => {
    if (helpTooltipElement.value) {
        helpTooltipElement.value.parentNode?.removeChild(helpTooltipElement.value);
    }
    helpTooltipElement.value = document.createElement('div');
    helpTooltipElement.value.className = 'ol-tooltip hidden';
    helpTooltip.value = new Overlay({
        element: helpTooltipElement.value,
        offset: [15, 0],
        positioning: 'center-left',
    });
    map.value?.addOverlay(helpTooltip.value);
};

</script>
<style>
.mygps-viewer {
    /* width: 88.5% !important;
    height: 91% !important;
    position: fixed;  */
}

.map {
    width: 100%;
    height: 100%;
}

#map .ol-zoom {
    top: 0.5em;
    left: 5em;
}

#map .ol-zoomslider {
    top: 4.5em;
    left: 5em;
    height: 200px;
}

#map .ol-overviewmap {
    bottom: 2.5em;
}

#map .ol-mouse-position {
    top: auto;
    bottom: 8px;
}


.popup {
    /* width: 250px; */
    background-color: rgba(50, 129, 255, 0.7);
    padding: 5px;
    border-radius: 10px;
    box-shadow: 0 0 15px rgb(177, 177, 177);

    .info {
        font-size: 14px;
        text-align: left;
        color: #fff;

        ul {
            padding-left: 0;

            li {
                list-style-type: none;
            }
        }
    }
}

.layout-container .layout-main .layout-main-scroll .layout-parent {
    padding: 0px !important;
}

.set {
    position: absolute;
    top: 0px;
    right: 0px;
    z-index: 99;
}

.btn {
    margin: 10px;
}

::v-deep(.hidden) {
    display: none;
}

::v-deep(.ol-tooltip) {
    position: relative;
    background: rgba(0, 0, 0, 0.5);
    border-radius: 4px;
    color: white;
    padding: 4px 8px;
    opacity: 0.7;
    white-space: nowrap;
    font-size: 12px;
    cursor: default;
    user-select: none;
}

::v-deep(.ol-tooltip-measure) {
    opacity: 1;
    font-weight: bold;
}

::v-deep(.ol-tooltip-static) {
    background-color: #ffcc33;
    color: black;
    border: 1px solid white;
}

::v-deep(.ol-tooltip-measure:before),
::v-deep(.ol-tooltip-static:before) {
    border-top: 6px solid rgba(0, 0, 0, 0.5);
    border-right: 6px solid transparent;
    border-left: 6px solid transparent;
    content: "";
    position: absolute;
    bottom: -6px;
    margin-left: -7px;
    left: 50%;
}

::v-deep(.ol-tooltip-static:before) {
    border-top-color: #ffcc33;
}
</style>